home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / demos / GL / flip / flip.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  21.3 KB  |  1,064 lines

  1. /*
  2.  * Copyright 1991, 1992, 1993, 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. /*
  18.  *    flip.c
  19.  * A complete face-lift for spin
  20.  * New, much better user interface
  21.  * Better lighting controls
  22.  *
  23.  * Now, all we need is a better object format...
  24.  * ... and buttons and panels
  25.  */
  26. #include <stdio.h>
  27. #include <gl/gl.h>
  28. #include <gl/device.h>
  29. #include "ui.h"
  30. #include "light.h"
  31. #include "flip.h"
  32.  
  33. #define HDWBUG    /* needed for CLOVER1 zfunction(GE_ZERO) hdwr bug */
  34.  
  35. /* Global variables */
  36.  
  37. static long XOrigin, YOrigin, Width, Height;
  38. static int UsePrefposition = 0, UsePrefsize = 0;
  39.  
  40. static int nobjs;    /* How many objects we're spinning */
  41. static flipobj **fobj;    /* Array of flipobj pointers */
  42. static flipobj lobj;    /* Stores lights' transformations */
  43. static float zmax;
  44. static float near, far, aspect;
  45. static int totalpolys = 0;
  46. static int update_view;    /* True if we need to constantly redraw object */
  47. static int show_performance = 0;
  48.  
  49. /* Tests for various hardware features */
  50. static int blending_supported;
  51. static int smoothlines_supported;
  52. static int clover1;
  53.  
  54. Matrix idmat =
  55. {    /* Useful Matrix to have around... */
  56.     {1.0, 0.0, 0.0, 0.0} ,
  57.     {0.0, 1.0, 0.0, 0.0} ,
  58.     {0.0, 0.0, 1.0, 0.0} ,
  59.     {0.0, 0.0, 0.0, 1.0}
  60. };
  61.  
  62. /* Prototypes for local functions */
  63. void main(int, char **), parse_args(int, char **);
  64. void init_windows(char *);
  65. void init_menus(void), do_menus(void);
  66. void read_files(void), draw_scene(void);
  67. void redraw_scene(void);
  68. void remember_view(float *, float *);
  69. void draw_rate(int);
  70. void draw_objects(void);
  71. void update_objeulers(void);
  72. void rand_rotation(float *);
  73. void alpha_on(void), alpha_off(void);
  74. void toggle_display(int), toggle_select(int);
  75. void toggle_alpha(int), toggle_drawtype(int);
  76. void toggle_swirl(int);
  77. void toggle_performance(void);
  78. void toggle_lightsource(int);
  79. void toggle_spinlights(void), toggle_displights(void);
  80. void select_all(void);
  81. void do_objmaterials(int);
  82. void remake_objmenu(int), remake_menus(void);
  83. void remake_lightmenu(void);
  84. void remake_mmenu(int), remake_dtmenu(int);
  85. void remake_lsmenu(void);
  86. void select_lmodel(int), remake_lmmenu(int);
  87. void anything_moving(int *);
  88.  
  89. void
  90. main(int argc, char **argv)
  91. {
  92.     parse_args(argc, argv);    /* This reads in the files, too */
  93.     init_windows(argv[0]);
  94.     make_lights();
  95.  
  96.     add_event(ANY, ESCKEY, UP, ui_exit, NULL);
  97.     qdevice(ESCKEY);
  98.     add_event(ANY, WINQUIT, ANY, ui_exit, NULL);
  99.     qdevice(WINQUIT);
  100.     add_event(ANY, REDRAW, ANY, redraw_scene, NULL);
  101.     qdevice(REDRAW);
  102.  
  103.     init_menus();    /* Add events for menu handling */
  104.     
  105.     add_update(&update_view, draw_scene, NULL);
  106.      add_event(ANY, ANY, ANY, anything_moving, (unsigned char *)&update_view);
  107.  
  108.     anything_moving(&update_view);
  109.  
  110.     qenter(REDRAW, 1);
  111.     update_objeulers();
  112.  
  113. /*
  114.  * Note:  All the add_events and add_updates that are added in ui()
  115.  * happen before those defined above; so, for example, the code for
  116.  * handling REDRAW inside ui.c will happen before the draw_scene
  117.  * specified above.  This is also why the anything_moving code works.
  118.  */
  119.     ui(remember_view);    /* Time is spent in ui, interacting */
  120.     gexit();
  121.     exit(0);
  122. }
  123.  
  124. /*
  125.  *    Called by ui interface, passed a float[4] that is a rotation
  126.  * specified in Euler paramaters and a float[3] that is xyz
  127.  * translation.  (no rotation is {0.0, 0.0, 0.0, 1.0}, no translation
  128.  * is {0.0, 0.0, 0.0})
  129.  */
  130. void
  131. remember_view(float *rot, float *trans)
  132. {
  133.     int i;
  134.  
  135.     if (lobj.select)    /* Moving lights, too */
  136.     {
  137.         vcopy(rot, lobj.espin);    /* vcopy copies 3 elements */
  138.         lobj.espin[3] = rot[3];    /* So copy fourth here */
  139.  
  140.         vadd(trans, lobj.trans, lobj.trans);
  141.     }
  142.  
  143.     for (i = 0; i < nobjs; i++)
  144.     {
  145.         if (fobj[i]->select)
  146.         {
  147.             vcopy(rot, fobj[i]->espin);
  148.             fobj[i]->espin[3] = rot[3];
  149.  
  150.             vadd(trans, fobj[i]->trans, fobj[i]->trans);
  151.         }
  152.     }
  153.     update_objeulers();    /* Spin those puppies */
  154.     draw_objects();
  155. }
  156.  
  157. /*
  158.  *    This function is called whenever a REDRAW event occurs.
  159.  */
  160. void
  161. redraw_scene(void)
  162. {
  163.     long xdim, ydim;
  164.  
  165.     reshapeviewport();
  166.     getsize(&xdim,&ydim);
  167.     aspect = (float) xdim/(float) ydim;
  168.  
  169.     perspective(750, (float) aspect, near, far);
  170.  
  171.     draw_scene();
  172. }
  173.  
  174. /*
  175.  *    This function is called whenever the user isn't interacting with
  176.  * the program (when ui_quiet is TRUE).  It just keeps on applying the
  177.  * last rotation and drawing the scene over and over.
  178.  */
  179. void
  180. draw_scene(void)
  181. {
  182.     int i;
  183.  
  184.     update_objeulers();
  185.     draw_objects();
  186. }
  187.  
  188. /*
  189.  *    This routine updates an object's total rotation by applying its
  190.  * spin rotation, and coming up with a new total rotation.  Also spins
  191.  * lights.
  192.  */
  193. void
  194. update_objeulers()
  195. {
  196.     int i;
  197.     for (i = 0; i < nobjs; i++)
  198.     {
  199.         add_eulers(fobj[i]->espin, fobj[i]->er, fobj[i]->er);
  200.     }
  201.     add_eulers(lobj.espin, lobj.er, lobj.er);
  202. }
  203.  
  204. /*
  205.  *    Draw the objects (and lights)
  206.  */
  207. void
  208. draw_objects()
  209. {
  210.     Matrix m;
  211.     int i;
  212.     int polysdrawn = 0;
  213.  
  214. #ifdef HDWBUG
  215.     /* Speedy clear */
  216.     if (clover1)
  217.         czclear(0, getgdesc(GD_ZMAX));
  218.     else
  219. #endif
  220.         czclear(0, getgdesc(GD_ZMIN));
  221.  
  222.     /* Transform the lights */
  223.     pushmatrix();
  224.     translate(lobj.trans[0], lobj.trans[1], lobj.trans[2]);
  225.     build_rotmatrix(m, lobj.er);
  226.     multmatrix(m);
  227.     rebind_lights();
  228.     if (lobj.display)    /* And maybe display them */
  229.         polysdrawn += draw_lights();
  230.     popmatrix();
  231.  
  232.     for (i = 0; i < nobjs; i++)
  233.     {
  234.         if (fobj[i]->display && !fobj[i]->ablend)
  235.         {
  236.             pushmatrix();
  237.             setmaterial(fobj[i]->material);
  238.  
  239.             /* Translate */
  240.             translate(fobj[i]->trans[0],
  241.                 fobj[i]->trans[1], fobj[i]->trans[2]);
  242.  
  243.             /* And then rotate */
  244.             build_rotmatrix(m, fobj[i]->er);
  245.             multmatrix(m);
  246.  
  247.             if (fobj[i]->type == SUBSMOOTHLINES
  248.                 && smoothlines_supported)
  249.             {
  250.                 if (!fobj[i]->ablend)
  251.                     blendfunction(BF_SA, BF_MSA);
  252.                 smoothline(TRUE);
  253.                 subpixel(TRUE);
  254.             }
  255.  
  256.             if (fobj[i]->swirl != 0)
  257.                 draw_swirl(fobj[i]);
  258.             else
  259.                 drawflipobj(fobj[i]);
  260.  
  261.             if (smoothlines_supported)
  262.             {
  263.                 if (!fobj[i]->ablend)
  264.                     blendfunction(BF_ONE, BF_ZERO);
  265.                 smoothline(FALSE);
  266.                 subpixel(FALSE);
  267.             }
  268.  
  269.             polysdrawn += fobj[i]->npoints / 4;
  270.             popmatrix();
  271.         }
  272.     }
  273. /* Alpha blend, if we're on a machine that can do it */
  274.     if (blending_supported)
  275.     {
  276.         alpha_on();
  277.         for (i = 0; i < nobjs; i++)
  278.         {
  279.             if (fobj[i]->display && fobj[i]->ablend)
  280.             {
  281.                 pushmatrix();
  282.                 setmaterial(NUM_MATERIALS+fobj[i]->material);
  283.  
  284.                 translate(fobj[i]->trans[0], 
  285.                     fobj[i]->trans[1], fobj[i]->trans[2]);
  286.  
  287.                 build_rotmatrix(m, fobj[i]->er);
  288.                 multmatrix(m);
  289.  
  290.                 if (fobj[i]->type == SUBSMOOTHLINES)
  291.                 {
  292.                     smoothline(TRUE);
  293.                     subpixel(TRUE);
  294.                 }
  295.  
  296.                 if (fobj[i]->swirl != 0)
  297.                     draw_swirl(fobj[i]);
  298.                 else
  299.                     drawflipobj(fobj[i]);
  300.  
  301.                 smoothline(FALSE);
  302.                 subpixel(FALSE);
  303.  
  304.                 polysdrawn += fobj[i]->npoints / 4;
  305.                 popmatrix();
  306.             }
  307.         }
  308.         alpha_off();
  309.     }
  310.  
  311.     if (show_performance)
  312.         draw_rate(polysdrawn);
  313.  
  314.     /* if (gotshare == TRUE)
  315.         testmsg(); */
  316.  
  317.     swapbuffers();
  318. }
  319.  
  320. #include <sys/types.h>
  321. #include <sys/times.h>
  322. #include <sys/param.h>
  323.  
  324. #define FRAMES 60    /* Update polygons/sec every FRAMES frames */
  325. void
  326. draw_rate(n)
  327. int n;
  328. {
  329.     static int numdrawn = 0;
  330.     static long lastt = 0;
  331.     static int frames = 0;
  332.     struct tms buf;
  333.     Matrix tm;
  334.     static char s[128];
  335.  
  336.     numdrawn += n;
  337.  
  338.     if (lastt == 0 && s[0] == 0)
  339.     {
  340.         sprintf(s, "%d polygons per frame", n);
  341.         lastt = times(&buf);
  342.     }
  343.     if (++frames >= FRAMES)
  344.     {
  345.         long t, et;
  346.  
  347.         t = times(&buf);
  348.         et = t - lastt;
  349.  
  350.         sprintf(s, "%d polygons/frame, %d frames/second, %d polys/sec",
  351.             n,
  352.             frames * HZ / et,
  353.             numdrawn * HZ / et);
  354.         frames = 0;
  355.         lastt = t;
  356.         numdrawn = 0;
  357.     }
  358.  
  359.     mmode(MPROJECTION);
  360.     getmatrix(tm);
  361.     ortho2(0.0, 100.0, 0.0, 100.0);
  362.     mmode(MVIEWING);
  363.     pushmatrix();
  364.     loadmatrix(idmat);
  365.  
  366.     cmov2i(3, 3);
  367.     cpack(0xffffff00);
  368.     if (getgdesc(GD_BITS_NORM_SNG_RED) != 3)
  369.        charstr(s);
  370.  
  371.     mmode(MPROJECTION);
  372.     loadmatrix(tm);
  373.     mmode(MVIEWING);
  374.     popmatrix();
  375. }
  376.  
  377. /*
  378.  * Initialize graphics
  379.  */
  380. void
  381. init_windows(title)
  382. char *title;
  383. {
  384.     long xorg, yorg, xdim, ydim;
  385.     char machinetype[20];
  386.  
  387.     if (getgdesc(GD_BITS_NORM_SNG_RED) == 0)
  388.     {
  389.         system("inform 'Your system must support RGB mode to run flip'");
  390.         exit(1);
  391.     }
  392.     if (getgdesc(GD_BITS_NORM_ZBUFFER) == 0)
  393.     {
  394.         system("inform 'Your system must have a z-buffer to run flip'");
  395.         exit(1);
  396.     }
  397.     if (getgdesc(GD_LINESMOOTH_RGB))
  398.         smoothlines_supported = 1;
  399.     else smoothlines_supported = 0;
  400.     if (getgdesc(GD_BLEND))
  401.         blending_supported = 1;
  402.     else
  403.         blending_supported = 0;
  404.  
  405.     gversion(machinetype);
  406.     if (strncmp(machinetype, "GL4D-", strlen("GL4DG-")) == 0)
  407.         clover1 = 1;
  408.     else clover1 = 0;
  409.  
  410.     if (UsePrefposition)
  411.         prefposition(XOrigin, XOrigin + Width - 1, YOrigin, 
  412.         YOrigin + Height - 1);
  413.     else if (UsePrefsize)
  414.         prefsize(Width, Height);
  415.  
  416.     /* Open with the executable's name (stripped of directory) */
  417.     {
  418.         char *t, *strrchr(char *, int);
  419.         /* testshare(""); */
  420.         winopen((t=strrchr(title, '/')) != NULL ? t+1 : title);
  421.     }
  422.     wintitle(title);
  423.  
  424.     reshapeviewport();
  425.     getsize(&xdim,&ydim);
  426.     aspect = (float) xdim/(float) ydim;
  427.  
  428.     RGBmode();
  429.     if (getgdesc(GD_BITS_NORM_DBL_RED) != 0)
  430.         doublebuffer();
  431.     gconfig();
  432.  
  433.     zbuffer(TRUE);
  434.  
  435. #ifdef HDWBUG 
  436.     if (clover1)
  437.     {
  438. /* workaround for CLOVER1 bug */
  439. /*        lsetdepth(getgdesc(GD_ZMIN), getgdesc(GD_ZMAX)); */
  440.         setdepth(getgdesc(GD_ZMIN), getgdesc(GD_ZMAX));
  441.     }
  442.     else
  443.     {
  444. #endif
  445.     /* Setup to use simultaneous z and color buffer clear */
  446.         zfunction(ZF_GEQUAL);
  447.         lsetdepth(getgdesc(GD_ZMAX), getgdesc(GD_ZMIN));
  448. #ifdef HDWBUG
  449.     }
  450. #endif
  451.  
  452.     near = 0.2;        /* Should be smarter about clipping planes */
  453.     far = 1.1 + zmax + 3.0;
  454.     mmode(MPROJECTION);
  455.     perspective(750, (float) aspect, near, far);
  456.     mmode(MVIEWING);
  457.     loadmatrix(idmat);
  458.     translate(0.0, 0.0, -1.1);
  459. }
  460.  
  461. void
  462. parse_args(argc, argv)
  463. int argc;
  464. char **argv;
  465. {
  466.     int whichobj=0;    /* Which one we're doing now */
  467.     int i, c, err, still;
  468.     float objzmax, objmaxpoint();
  469.     extern int optind;
  470.     extern char *optarg;
  471.  
  472.     still = FALSE;    /* Spin around like crazy by default */
  473.  
  474.     /*
  475.      * If on a machine that can't double-buffer, stay still!
  476.      */
  477.     if (getgdesc(GD_BITS_NORM_DBL_RED) == 0)
  478.         still = TRUE;
  479.  
  480.     err = FALSE; 
  481.     while ((c = getopt(argc, argv, "W:sh")) != -1)
  482.     {
  483.         switch(c)
  484.         {
  485.             case 'W': /* provide x1,y1,x2,y2  or just xsize, ysize */
  486.             if (4 == sscanf(optarg, "%d,%d,%d,%d", 
  487.                 &XOrigin, &YOrigin, &Width, &Height))  {
  488.                 UsePrefposition = 1;
  489.             } else if (2 == sscanf(optarg, "%d,%d", 
  490.                 &Width, &Height))  {
  491.                 UsePrefsize = 1;
  492.             } else  {
  493.                 err = 1;
  494.             }
  495.             break;
  496.  
  497.             case 's':    /* Still (don't move) */
  498.             still = TRUE;
  499.             break;
  500.             case 'h':    /* Help */
  501.             default:
  502.             err=TRUE;
  503.             break;
  504.         }
  505.     }
  506.  
  507.     /* First pass, figure out how many arguments */
  508.     for (i = optind; i < argc; i++)
  509.     {
  510.         if (argv[i][0] != '-')
  511.             ++nobjs;
  512.     }
  513.  
  514.     if (err || nobjs==0 )
  515.     {
  516.         fprintf(stderr, "Usage:\n");
  517.         fprintf(stderr, "%s [-sh] [-W[xorg,yorg,]width,height] modelname [modelname]\n",argv[0]);
  518.         fprintf(stderr, "\t-s Means stay still, objects won't get random rotation\n");
  519.         fprintf(stderr, "\t-h Help (this message)\n");
  520.         exit(1);
  521.     }
  522.  
  523.     fobj = (flipobj **)malloc(
  524.         sizeof(flipobj *) * nobjs);
  525.     for (i = optind; i < argc; i++)
  526.     {
  527.         char temp[64];
  528.         FILE *fp;
  529.         int j, loaded;
  530.  
  531. /*
  532.  *    First check to see if this object has already been loaded
  533.  */
  534.         loaded = (-1);
  535.         for (j = optind; j < i; j++)
  536.         {
  537.             if (strcmp(argv[j], argv[i]) == 0)
  538.             {
  539.                 loaded = j-optind;
  540.             }
  541.         }
  542.         if (loaded == (-1))
  543.         {
  544. /*
  545.  * Ok, try to read in first from current directory,
  546.  *    then from the demos directory
  547.  */
  548.             if ((fp = fopen(argv[i], "r")) != NULL)
  549.             {
  550.                 fclose(fp);
  551.                 fobj[whichobj] = readflipobj(argv[i]);
  552.             }
  553.             else
  554.             {
  555.                 strcpy(temp, MODELDIR);
  556.                 strcat(temp, argv[i]);
  557.                 fobj[whichobj] = readflipobj(temp);
  558.             }
  559.             if (fobj[whichobj] == NULL)
  560.             {
  561.                 sprintf(temp, "%s, error reading %s:",
  562.                     argv[0], argv[i]);
  563.                 perror(temp);
  564.                 exit(1);
  565.             }
  566.             {
  567.                 char *t, *strrchr(char *, int);
  568.                 t = strrchr(argv[i], '/');
  569.                 t =  (t == NULL) ? argv[i] : t+1 ;
  570.                 fobj[whichobj]->fname = t;
  571.             }
  572.         }
  573.         else
  574.         {    /* Share data with previous instance */
  575.             fobj[whichobj] = (flipobj *)malloc(sizeof(flipobj));
  576.             memcpy(fobj[whichobj], fobj[loaded], sizeof(flipobj));
  577.         }
  578. /* Set-up defaults */
  579.         fobj[whichobj]->display = TRUE;
  580.         fobj[whichobj]->type = POLYGONS;    /* draw polygons */
  581.         fobj[whichobj]->select = FALSE;
  582.         fobj[whichobj]->material = 2;
  583.         fobj[whichobj]->ablend = FALSE;
  584.         fobj[whichobj]->swirl = 0;
  585.         vzero(fobj[whichobj]->trans);
  586.  
  587.         vzero(fobj[whichobj]->er);
  588.         fobj[whichobj]->er[3] = 1.0;
  589.         if (still)
  590.         {
  591.             vzero(fobj[whichobj]->espin);
  592.             fobj[whichobj]->espin[3] = 1.0;
  593.         }
  594.         else
  595.         {
  596.             rand_rotation(fobj[whichobj]->espin);
  597.         }
  598.  
  599.         totalpolys += (fobj[whichobj]->npoints) / 4;
  600.         if ((objzmax = objmaxpoint(fobj[whichobj])) > zmax)
  601.             zmax = objzmax;
  602.         ++whichobj;
  603.     }
  604.     fobj[0]->select = TRUE;
  605.  
  606. /* Initialize lights */
  607.     lobj.select = FALSE;    /* Don't rotate by default */
  608.     lobj.display = TRUE;    /* But do display */
  609.     vzero(lobj.er);    /* Start with no rotation */
  610.     lobj.er[3] = 1.0;
  611.     vzero(lobj.espin);    /* no spin */
  612.     lobj.espin[3] = 1.0;
  613.     vzero(lobj.trans);    /* and no translation */
  614. }
  615. void
  616. rand_rotation(e)
  617. float *e;
  618. {
  619.     static int init = 0;
  620.     int i;
  621.     float a[3];    /* Pick a random axis to rotate about */
  622.     float phi;    /* And a speed of rotation */
  623.     extern double drand48(void);
  624.     extern void srand48(long);
  625.     
  626.     if (!init)
  627.     {
  628.         srand48(getpid());
  629.         init = 1;
  630.     }
  631.     for (i = 0 ; i < 3 ; i++)
  632.         a[i] = drand48() - 0.5;
  633.  
  634. /* Un-comment this out to get random rotation speeds
  635.  *    phi = drand48() * .3;
  636.  */
  637.     phi = 0.1;
  638.  
  639. /* Now figure out Euler paramaters for given axis */
  640.     axis_to_euler(a, phi, e);
  641. }
  642.  
  643. static int lights[NUM_LIGHTS] ;
  644.  
  645. /*
  646.  * Define the lighting model, lights, and initial material 
  647.  */
  648. make_lights()
  649. {
  650.     int i;
  651.     for (i = 0 ; i < NUM_LIGHTS ; i++)
  652.         lights[i] = 0;    /* Off */
  653.  
  654.     defineshading();    /* lmdef everything used */
  655.     
  656.     setmodel(0);    /* Use infinite viewer */
  657.  
  658.     switch_light(0);    /* Infinite White on */
  659.     lights[0] = 1;
  660.     switch_light(2);    /* Infinite Yellow on */
  661.     lights[2] = 1;
  662. }
  663.  
  664. static long flipmenu;    /* Top-level menu */
  665. static long lightmenu;    /* Lights */
  666. static long lmmenu;    /* Light models submenu */
  667. static long lsmenu;    /* Light sources submenu */
  668. static long *objmenus;    /* Menu for each object */
  669. static long *mmenus;    /* Materials for each object */
  670. static long *dtmenus;    /* Draw types for each object */
  671.  
  672. void
  673. init_menus()
  674. {
  675.     int i;
  676.     char temp[64];
  677.  
  678.     lsmenu = newpup();
  679.     remake_lsmenu();
  680.     lmmenu = newpup();
  681.     remake_lmmenu(0);
  682.     lightmenu = newpup();
  683.     remake_lightmenu();
  684.  
  685.     objmenus = (long *) malloc(sizeof(long) * nobjs);
  686.     dtmenus = (long *) malloc(sizeof(long) * nobjs);
  687.     mmenus = (long *) malloc(sizeof(long) * nobjs);
  688.     for (i = 0; i < nobjs; i++)
  689.     {
  690.         mmenus[i] = newpup();
  691.         remake_mmenu(i);
  692.         dtmenus[i] = newpup();
  693.         remake_dtmenu(i);
  694.         objmenus[i] = newpup();
  695.         remake_objmenu(i);
  696.     }
  697.     flipmenu = newpup();
  698.  
  699.     remake_menus();
  700.     
  701.     qdevice(RIGHTMOUSE);
  702.     add_event(ANY, RIGHTMOUSE, DOWN, do_menus, NULL);
  703. }
  704. void
  705. do_menus()
  706. {
  707.     dopup(flipmenu);
  708.     draw_scene();
  709. }
  710.  
  711. /*
  712.  *    Scheme for re-making minumum number of menus:
  713.  * don't remake the whole structure, just what could have possibly
  714.  * changed (the lowest-level object menus).  Assumes all lowest-level
  715.  * object menus are already made.
  716.  */
  717. void
  718. remake_menus(void)
  719. {
  720.     int i, j;
  721.     char temp[64];
  722.  
  723.     freepup(flipmenu);
  724.     flipmenu = newpup();
  725.     addtopup(flipmenu, "Flip %t");
  726.     addtopup(flipmenu, "Lights %m", lightmenu);
  727.     for (i = 0; i < nobjs; i++)
  728.     {
  729.         sprintf(temp, "%s %%m", fobj[i]->fname);
  730.         addtopup(flipmenu, temp, objmenus[i]); 
  731.     }
  732.     if (nobjs > 1)
  733.         addtopup(flipmenu, "Select all %f", select_all);
  734.     if (show_performance)
  735.         addtopup(flipmenu, "No Performance Numbers %f", toggle_performance);
  736.     else
  737.         addtopup(flipmenu, "Show Performance Numbers %f", toggle_performance);
  738.     addtopup(flipmenu, "Exit %f", ui_exit);
  739. }
  740.  
  741. void
  742. remake_lightmenu(void)
  743. {
  744.     freepup(lightmenu);
  745.     lightmenu = newpup();
  746.     addtopup(lightmenu, "Sources %m", lsmenu);
  747.     addtopup(lightmenu, "Lighting Models %m", lmmenu);
  748.     if (lobj.select == TRUE)
  749.         addtopup(lightmenu, "Deselect lights %f",toggle_spinlights);
  750.     else
  751.         addtopup(lightmenu, "Select lights %f",toggle_spinlights);
  752.     if (lobj.display == TRUE)
  753.         addtopup(lightmenu, "Hide local lights %f", toggle_displights);
  754.     else
  755.         addtopup(lightmenu, "Show local lights %f", toggle_displights);
  756. }
  757.  
  758. void
  759. remake_mmenu(int n)
  760. {
  761.     int i, j, start;
  762.     char temp[64];
  763.     start = n*NUM_MATERIALS;
  764.  
  765.     freepup(mmenus[n]);
  766.     mmenus[n] = newpup();
  767.     addtopup(mmenus[n], "Material Properties %t %F", do_objmaterials);
  768.     for (j = 0 ; j < NUM_MATERIALS ; j++)
  769.     {
  770.         sprintf(temp, "%s %%x%d", matnames[j], start+j);
  771.         addtopup(mmenus[n], temp);
  772.         setpup(mmenus[n], j+1, (fobj[n]->material==j)
  773.                     ? PUP_CHECK : PUP_BOX);
  774.     }
  775. }
  776.  
  777. void
  778. remake_dtmenu(int n)
  779. {
  780.     char temp[64];
  781.     int i;
  782.     
  783.     i = n * (int)NUM_DrawTypes;
  784.  
  785.     freepup(dtmenus[n]);
  786.     dtmenus[n] = newpup();
  787.     addtopup(dtmenus[n], "Drawing Modes %t %F", toggle_drawtype);
  788.     sprintf(temp, "Polygons %%x%d", i+(int)POLYGONS);
  789.     addtopup(dtmenus[n], temp);
  790.     setpup(dtmenus[n], 1, (fobj[n]->type==POLYGONS) ? PUP_CHECK : PUP_BOX);
  791.     sprintf(temp, "Lines %%x%d", i+(int)LINES);
  792.     addtopup(dtmenus[n], temp);
  793.     setpup(dtmenus[n], 2, (fobj[n]->type==LINES) ? PUP_CHECK : PUP_BOX);
  794.     if (smoothlines_supported)
  795.     {
  796.         sprintf(temp, "Subpixel, antialised lines %%x%d", 
  797.                 i+(int)SUBSMOOTHLINES);
  798.         addtopup(dtmenus[n], temp);
  799.         setpup(dtmenus[n], 3, (fobj[n]->type == SUBSMOOTHLINES)
  800.                 ? PUP_CHECK : PUP_BOX);
  801.     }
  802. }
  803.  
  804. void
  805. remake_objmenu(n)
  806. int n;
  807. {
  808.     char temp[64];
  809.  
  810.     freepup(objmenus[n]);
  811.     objmenus[n] = newpup();
  812.  
  813.     if (fobj[n]->display == TRUE)
  814.         sprintf(temp, "Hide %%f %%x%d", n);
  815.     else
  816.         sprintf(temp, "Show %%f %%x%d", n);
  817.     addtopup(objmenus[n], temp, toggle_display);
  818.  
  819.     if (fobj[n]->select == TRUE)
  820.         sprintf(temp, "Deselect %%f %%x%d", n);
  821.     else
  822.         sprintf(temp, "Select %%f %%x%d", n);
  823.     addtopup(objmenus[n], temp, toggle_select);
  824.  
  825.     addtopup(objmenus[n], "Object Materials %m", mmenus[n]);
  826.  
  827.     if (blending_supported)
  828.     {
  829.         if (fobj[n]->ablend == TRUE)
  830.             sprintf(temp, "Make Opaque %%f %%x%d", n);
  831.         else
  832.             sprintf(temp, "Make Transparent %%f %%x%d", n);
  833.         addtopup(objmenus[n], temp, toggle_alpha);
  834.     }
  835.  
  836.     addtopup(objmenus[n], "Display Object as... %m", dtmenus[n]);
  837.  
  838.     if (fobj[n]->swirl == 0)
  839.         sprintf(temp, "Swirl me %%f %%x%d", n);
  840.     else
  841.         sprintf(temp, "Stop swirling %%f %%x%d", n);
  842.     addtopup(objmenus[n], temp, toggle_swirl);
  843. }
  844.  
  845. void
  846. toggle_performance(void)
  847. {
  848.     show_performance = !show_performance;
  849.     
  850.     remake_menus();
  851. }
  852.  
  853. void
  854. do_objmaterials(int n)
  855. {
  856.     int obj, m;
  857.  
  858.     obj = n/NUM_MATERIALS;
  859.     m = n % NUM_MATERIALS;
  860.  
  861.     fobj[obj]->material = m;
  862.     remake_mmenu(obj);
  863.     remake_objmenu(obj);
  864.     remake_menus();
  865. }
  866.  
  867. void
  868. toggle_spinlights(void)
  869. {
  870.     lobj.select = !lobj.select;
  871.  
  872.     remake_lightmenu();
  873.     remake_menus();
  874. }
  875. void
  876. toggle_display(n)
  877. int n;
  878. {
  879.     fobj[n]->display = !fobj[n]->display;
  880.  
  881.     remake_objmenu(n);
  882.     remake_menus();
  883. }
  884. void
  885. toggle_drawtype(n)
  886. int n;
  887. {
  888.     int obj;
  889.     enum DrawType dt;
  890.  
  891.     obj = n / (int)NUM_DrawTypes;
  892.     dt = (enum DrawType)(n % (int)NUM_DrawTypes);
  893.  
  894.     fobj[obj]->type = dt;
  895.  
  896.     remake_dtmenu(obj);
  897.     remake_objmenu(obj);
  898.     remake_menus();
  899. }
  900. void
  901. toggle_displights(void)
  902. {
  903.     lobj.display = !lobj.display;
  904.  
  905.     remake_lightmenu();
  906.     remake_menus();
  907. }
  908. void
  909. toggle_alpha(n)
  910. int n;
  911. {
  912.     fobj[n]->ablend = !fobj[n]->ablend;
  913.  
  914.     remake_objmenu(n);
  915.     remake_menus();
  916. }
  917. void
  918. toggle_swirl(n)
  919. int n;
  920. {
  921.     fobj[n]->swirl = !fobj[n]->swirl;
  922.  
  923.     remake_objmenu(n);
  924.     remake_menus();
  925. }
  926.  
  927. void
  928. select_all()
  929. {
  930.     int i;
  931.     for (i = 0; i < nobjs; i++)
  932.     {
  933.         if (fobj[i]->select == FALSE)
  934.         {
  935.             fobj[i]->select = TRUE;
  936.             remake_objmenu(i) ;
  937.         }
  938.     }
  939.     remake_menus() ;
  940. }
  941.  
  942. void
  943. toggle_select(n)
  944. int n;
  945. {
  946.     int t ;
  947.  
  948.     fobj[n]->select = !fobj[n]->select;
  949.  
  950.     remake_objmenu(n);
  951.     remake_menus();
  952. }
  953.  
  954. void
  955. toggle_lightsource(int ls)
  956. {
  957.     switch_light(ls);
  958.     lights[ls] = !lights[ls];
  959.  
  960.     remake_lsmenu();
  961.     remake_lightmenu();
  962.     remake_menus();
  963. }
  964.  
  965. void
  966. remake_lsmenu(void)
  967. {
  968.     int i;
  969.     char temp[64];
  970.  
  971.     freepup(lsmenu);
  972.     lsmenu = newpup();
  973.     addtopup(lsmenu, "Light Sources %t %F", toggle_lightsource);
  974.     for (i = 0 ; i < NUM_LIGHTS; i++)
  975.     {
  976.         sprintf(temp, "%s %%x%d", lightnames[i], i);
  977.         addtopup(lsmenu, temp);
  978.         setpup(lsmenu, i+1, lights[i] ? PUP_CHECK : PUP_BOX);
  979.     }
  980. }
  981.  
  982. void
  983. select_lmodel(int n)
  984. {
  985.     setmodel(n);
  986.     remake_lmmenu(n);
  987.     remake_lightmenu();
  988.     remake_menus();
  989. }
  990.  
  991. void
  992. remake_lmmenu(int n)
  993. {
  994.     int i;
  995.     char temp[64];
  996.     
  997.     freepup(lmmenu);
  998.     lmmenu = newpup();
  999.     addtopup(lmmenu, "Light Models %t %F", select_lmodel);
  1000.     for (i = 0 ; i < NUM_LMODELS; i++)
  1001.     {
  1002.         sprintf(temp, "%s %%x%d", lmodelnames[i], i);
  1003.         addtopup(lmmenu, temp, select_lmodel);
  1004.         setpup(lmmenu, i+1, (i == n ? PUP_CHECK : PUP_BOX));
  1005.     }
  1006. }
  1007.  
  1008. void
  1009. alpha_on()
  1010. {
  1011.     blendfunction(BF_SA, BF_MSA);
  1012.     zwritemask(0x0);
  1013. }
  1014.  
  1015. void
  1016. alpha_off()
  1017. {
  1018.     blendfunction(BF_ONE, BF_ZERO);
  1019.     zwritemask(0xffffff);
  1020. }
  1021.  
  1022. /*
  1023.  * This function figures out if anything is moving.  If it is, it
  1024.  * returns TRUE in ptr; if not, FALSE
  1025.  */
  1026. void
  1027. anything_moving(int *ptr)
  1028. {
  1029.     int spinning(float *);
  1030.  
  1031.     *ptr = FALSE;
  1032.  
  1033.     if (ui_quiet)
  1034.     {
  1035.         int i;
  1036.     
  1037.         /* If lights are spinning... */
  1038.         if (spinning(lobj.espin))
  1039.             *ptr = TRUE;
  1040.         /* Or objects are spinning or swirling, redraw */
  1041.         else for (i = 0; i < nobjs;  i++)
  1042.         {
  1043.             if (fobj[i]->display &&
  1044.                 (fobj[i]->swirl ||
  1045.                 spinning(fobj[i]->espin)))
  1046.             {
  1047.                 *ptr = TRUE;
  1048.             }
  1049.         }
  1050.     }
  1051. }
  1052.  
  1053. static int
  1054. spinning(float *r)
  1055. {
  1056.     float sum;
  1057.  
  1058.     sum = r[0] + r[1] + r[2] + r[3];
  1059.     if (sum > 0.999 && sum < 1.001)
  1060.         return FALSE;
  1061.     else
  1062.         return TRUE;
  1063. }
  1064.